﻿using HslControls;
using HslControls.WPF;
using Modbus.Device;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PressureReader
{
    public partial class Form1 : Form
    {
        /// <summary>
        /// 私有串口实例
        /// </summary>
        private SerialPort serialPort = new SerialPort();

        /// <summary>
        /// 私有ModbusRTU主站字段
        /// </summary>
        private static IModbusMaster master;

        private Queue<float> pressureData = new Queue<float>();
        private int maxDataPoints = 100; // 设置最大容量


        private StreamWriter csvWriter = null;
        private string csvFilePath = @"C:\Data\PressureLog.csv"; // 替换为你自己的路径
        private bool isLogging = false;

        public void AddData(float newData)
        {
            //最大点数等于曲线的宽度
            maxDataPoints = hslCurveHistory1.Width;

            if (pressureData.Count >= maxDataPoints)
            {
                pressureData.Dequeue(); // 移除最早的数据
            }
            pressureData.Enqueue(newData); // 添加新数据
        }
        public float[] GetCurrentData()
        {
            return pressureData.ToArray();
        }


        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //设置可选串口
            cbxPort.Items.AddRange(SerialPort.GetPortNames());
            //如果串口列表为空,则提示无串口
            if (cbxPort.Items.Count == 0)
            {
                cbxPort.Items.Add("无串口!");
                MessageBox.Show("No Serial Port Found!");
            }
            

            //设置可选波特率
            cbxBaudRate.Items.AddRange(new object[] { 9600, 19200 });
            //设置可选奇偶校验
            cbxParity.Items.AddRange(new object[] { "None", "Odd", "Even", "Mark", "Space" });
            //设置可选数据位
            cbxDataBits.Items.AddRange(new object[] { 5, 6, 7, 8 });
            //设置可选停止位
            cbxStopBits.Items.AddRange(new object[] { 1, 1.5, 2 });
            //设置读写模式
            cbxMode.Items.AddRange(new object[] {
                "读取输出线圈",
                "读取离散输入",
                "读取保持型寄存器",
                "读取输入寄存器",
                "写入单个线圈",
                "写入多个线圈",
                "写入单个寄存器",
                "写入多个寄存器"
            });

            //设置默认选中项
            cbxPort.SelectedIndex = 0;
            cbxBaudRate.SelectedIndex = 0;
            cbxParity.SelectedIndex = 0;
            cbxDataBits.SelectedIndex = 3;
            cbxStopBits.SelectedIndex = 0;
            cbxMode.SelectedIndex = 0;

            nudLength.Minimum = 1;
            nudSlaveID.Minimum = 1;
            nudStartAdr.Minimum = 0;


            //设置为默认输入法，即为英文半角
            rbxRWMsg.ImeMode = ImeMode.Disable;

            nudreadCycle.Minimum  = 20;
            nudreadCycle.Maximum = 100000;
            nudreadCycle.Value = 100;
            //增加一条曲线
            hslCurveHistory1.SetLeftCurve("压力", GetCurrentData(), Color.Red, HslControls.CurveStyle.Curve);


            hslCurveHistory1.ScrollToRight(); // 直接滚动到最右侧

            




        }

        private void cbxMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            rbxRWMsg.Clear();
            if (cbxMode.SelectedItem.ToString().Contains("读取"))
            {
                btnRW.Text = "读取";
                rbxRWMsg.Enabled = false;
                nudLength.Enabled = true;
            }
            else
            {
                btnRW.Text = "写入";
                rbxRWMsg.Enabled = true;
                nudLength.Enabled = false;
            }
        }
        /// <summary>
        /// 读写事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRW_Click(object sender, EventArgs e)
        {
            //打开串口
            if (!serialPort.IsOpen)
            {//设定串口参数
                serialPort.PortName = cbxPort.SelectedItem.ToString();
                serialPort.BaudRate = (int)cbxBaudRate.SelectedItem;
                serialPort.Parity = GetSelectedParity();
                serialPort.DataBits = (int)cbxDataBits.SelectedItem;
                serialPort.StopBits = GetSelectedStopBits();
                serialPort.Open();
                btopen.Text = "关闭串口";
                //创建ModbusRTU主站实例
                master = ModbusSerialMaster.CreateRtu(serialPort);
            }

            //根据选择的模式进行读写
            switch (cbxMode.SelectedItem.ToString())
            {
                case "读取输出线圈":
                    SetMsg(ReadCoils().ToList());
                    break;
                case "读取离散输入":
                    SetMsg(ReadInputs().ToList());
                    break;
                case "读取保持型寄存器":
                    SetMsg(ReadHoldingRegisters().ToList());
                    break;
                case "读取输入寄存器":
                    SetMsg(ReadInputRegisters().ToList());
                    break;
                case "写入单个线圈":
                    if (rbxRWMsg.Text.Contains(","))
                    {
                        MessageBox.Show("输入值过多");
                        serialPort.Close();
                        return;
                    }
                    WriteSingleCoil();
                    break;
                case "写入多个线圈":
                    WriteArrayCoil();
                    break;
                case "写入单个寄存器":
                    if (rbxRWMsg.Text.Contains(","))
                    {
                        MessageBox.Show("输入值过多");
                        serialPort.Close();
                        return;
                    }
                    WriteSingleRegister();
                    break;
                case "写入多个寄存器":
                    WriteArrayRegister();
                    break;
                default:
                    break;
            }
        }
        /// <summary>
        /// 更新写入值计数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void rbxRWMsg_TextChanged(object sender, EventArgs e)
        {
            Debug.WriteLine("进来过这里");
            nudLength.Value = Regex.Matches(rbxRWMsg.Text, ",").Count + 1;
        }

        /// <summary>
        /// 获取窗体选中的奇偶校验
        /// </summary>
        /// <returns></returns>
        private Parity GetSelectedParity()
        {
            switch (cbxParity.SelectedItem.ToString())
            {
                case "Odd":
                    return Parity.Odd;
                case "Even":
                    return Parity.Even;
                case "Mark":
                    return Parity.Mark;
                case "Space":
                    return Parity.Space;
                case "None":
                default:
                    return Parity.None;
            }
        }

        /// <summary>
        /// 获取窗体选中的停止位
        /// </summary>
        /// <returns></returns>
        private StopBits GetSelectedStopBits()
        {
            switch (Convert.ToDouble(cbxStopBits.SelectedItem))
            {
                case 1:
                    return StopBits.One;
                case 1.5:
                    return StopBits.OnePointFive;
                case 2:
                    return StopBits.Two;
                default:
                    return StopBits.One;
            }
        }
        /// <summary>
        /// 写入单个线圈
        /// </summary>
        private void WriteSingleCoil()
        {
            bool result = false;
            if (rbxRWMsg.Text.Equals("true", StringComparison.OrdinalIgnoreCase) || rbxRWMsg.Text.Equals("1", StringComparison.OrdinalIgnoreCase))
            {
                result = true;
            }
            master.WriteSingleCoil((byte)nudSlaveID.Value, (ushort)nudStartAdr.Value, result);
        }

        /// <summary>
        /// 批量写入线圈
        /// </summary>
        private void WriteArrayCoil()
        {
            List<string> strList = rbxRWMsg.Text.Split(',').ToList();

            List<bool> result = new List<bool>();

            strList.ForEach(m => result.Add(m.Equals("true", StringComparison.OrdinalIgnoreCase) || m.Equals("1", StringComparison.OrdinalIgnoreCase)));

            master.WriteMultipleCoils((byte)nudSlaveID.Value, (ushort)nudStartAdr.Value, result.ToArray());
        }

        /// <summary>
        /// 写入单个寄存器
        /// </summary>
        private void WriteSingleRegister()
        {
            ushort result = Convert.ToUInt16(rbxRWMsg.Text);

            master.WriteSingleRegister((byte)nudSlaveID.Value, (ushort)nudStartAdr.Value, result);
        }

        /// <summary>
        /// 批量写入寄存器
        /// </summary>
        private void WriteArrayRegister()
        {
            List<string> strList = rbxRWMsg.Text.Split(',').ToList();

            List<ushort> result = new List<ushort>();

            strList.ForEach(m => result.Add(Convert.ToUInt16(m)));

            master.WriteMultipleRegisters((byte)nudSlaveID.Value, (ushort)nudStartAdr.Value, result.ToArray());
        }

        /// <summary>
        /// 读取输出线圈
        /// </summary>
        /// <returns></returns>
        private bool[] ReadCoils()
        {
            return master.ReadCoils((byte)nudSlaveID.Value, (ushort)nudStartAdr.Value, (ushort)nudLength.Value);
        }

        /// <summary>
        /// 读取输入线圈
        /// </summary>
        /// <returns></returns>
        private bool[] ReadInputs()
        {
            return master.ReadInputs((byte)nudSlaveID.Value, (ushort)nudStartAdr.Value, (ushort)nudLength.Value);
        }

        /// <summary>
        /// 读取保持型寄存器
        /// </summary>
        /// <returns></returns>
        private ushort[] ReadHoldingRegisters()
        {
            return master.ReadHoldingRegisters((byte)nudSlaveID.Value, (ushort)nudStartAdr.Value, (ushort)nudLength.Value);
        }

        /// <summary>
        /// 读取输入寄存器
        /// </summary>
        /// <returns></returns>
        private ushort[] ReadInputRegisters()
        {
            return master.ReadInputRegisters((byte)nudSlaveID.Value, (ushort)nudStartAdr.Value, (ushort)nudLength.Value);
        }
        /// <summary>
        /// 界面显示读取结果
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="result"></param>
        private void SetMsg<T>(List<T> result)
        {
            string msg = string.Empty;

            result.ForEach(m => msg += $"{m} ");

            rbxRWMsg.Text = msg.Trim();
        }

        private void btopen_Click(object sender, EventArgs e)
        {
            //打开串口
            if (!serialPort.IsOpen)
            {//设定串口参数
                serialPort.PortName = cbxPort.SelectedItem.ToString();
                serialPort.BaudRate = (int)cbxBaudRate.SelectedItem;
                serialPort.Parity = GetSelectedParity();
                serialPort.DataBits = (int)cbxDataBits.SelectedItem;
                serialPort.StopBits = GetSelectedStopBits();
                serialPort.Open();
                btopen.Text = "关闭串口";
                //创建ModbusRTU主站实例
                master = ModbusSerialMaster.CreateRtu(serialPort);
            }
            else
            {
                
                serialPort.Close();
                btopen.Text = "打开串口";
            }

        }

        private void btRflash_Click(object sender, EventArgs e)
        {
            //清空cbxPort
            cbxPort.Items.Clear();

            //设置可选串口
            cbxPort.Items.AddRange(SerialPort.GetPortNames());
            //如果串口列表为空,则提示无串口
            if (cbxPort.Items.Count == 0)
            {
                cbxPort.Items.Add("无串口!");
                MessageBox.Show("No Serial Port Found!");
            }
        }

      
        //周期性读取定时器
        private void timer1_Tick(object sender, EventArgs e)
        {
            //在定时器里面定时读取数据
            try
            {
                ushort[] resort = master.ReadHoldingRegisters((byte)nudSlaveID.Value, (ushort)nudStartAdr.Value, 1);
                //将resort打印出来
                Debug.WriteLine(nudSlaveID.Value.ToString() + nudStartAdr.Value.ToString() + "压力值" + resort[0]); ;
                float pressure = (short)(resort[0]);  //在这里得到press
                pressure = pressure / 10.0f;
                Preess.Text = pressure.ToString();

                AddData(pressure);

                hslCurveHistory1.SetLeftCurve("压力", GetCurrentData(), Color.Red, HslControls.CurveStyle.Curve);

                hslCurveHistory1.ScrollToRight(); // 直接滚动到最右侧

                hslCurveHistory1.ReferenceAxisLeft.Max = (float)Math.Ceiling(GetCurrentData().Max())+10; // 设置大于最大值的向上整数部分，如果最大值是 100.6  那就是 10
                hslCurveHistory1.ReferenceAxisLeft.Min = (float)Math.Ceiling(GetCurrentData().Min())-10; // 设置大于最大值的向上整数部分，如果最大值是 100.6  那
                //判断存储功能是否开启
                if (saveflag == 1)  //当前请求保存数据
                {
                    StartCsvLogging(); //创建文件
                    saveflag = 2; //正在保存数据
                }else if (saveflag == 2)
                {

                    LogPressureData(pressure);
                }else if (saveflag == 3)
                {
                    
                    StopCsvLogging();
                    saveflag = 0;
                    btStartSave.Text = "开始保存";
                }
            }
            catch { 
            }
        }

        private void btReadpress_Click(object sender, EventArgs e)
        {
            //判断串口是否打开
            if (serialPort.IsOpen)
            { 
                //判断定时器是否启动
                if (timer1.Enabled)
                {
                    timer1.Enabled = false;
                    btReadpress.Text = "开始读取";
                }
                else
                {
                    //设置time1的定时时间
                    timer1.Interval = Convert.ToInt32(nudreadCycle.Value);
                    timer1.Enabled = true;
                    btReadpress.Text = "停止读取";
                }
               
            }else
                MessageBox.Show("请先打开串口！");
        }

        private void numericUpDown3_ValueChanged(object sender, EventArgs e)
        {
            nudSlaveID.Value = numericUpDown3.Value;
        }

        private void numericUpDown2_ValueChanged(object sender, EventArgs e)
        {
            nudStartAdr.Value = numericUpDown2.Value;
        }
        private int saveflag = 0;
        //开始保存数据
        private void btStartSave_Click(object sender, EventArgs e)
        {
            //如果当前没有在保存数据
            if (saveflag == 0) //现在没有保存数据
            {
                btStartSave.Text  = "停止保存";
                saveflag = 1;  //可以开始保存数据
            }
            else if (saveflag == 1) //正常不存在这种情况
            {
                saveflag = 0;  //可以停止保存数据
            }
            else if (saveflag == 2) //当前正在保存数据
            {
                saveflag = 3;   //请求停止保存
            }
        }
     
        private void hslCurve1_Load(object sender, EventArgs e)
        {
           
                
        }



        public void StartCsvLogging()
        {
            if (isLogging) return;

            try
            { 
               
                csvFilePath = Path.Combine(Environment.CurrentDirectory, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.csv");
                tbPath.Text = csvFilePath;

                string directory = Path.GetDirectoryName(csvFilePath);
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                // 创建或覆盖文件
                csvWriter = new StreamWriter(csvFilePath, false, Encoding.UTF8);
                // 写入表头
                csvWriter.WriteLine("Timestamp,Pressure");
                csvWriter.Flush();

                isLogging = true;
                MessageBox.Show("CSV 日志已启动");
            }
            catch (Exception ex)
            {
                MessageBox.Show("无法创建 CSV 文件：" + ex.Message);
            }
        }

        public void LogPressureData(float pressure)
        {
            if (!isLogging || csvWriter == null) return;

            try
            {
                string line = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff},{pressure:F4}";
                csvWriter.WriteLine(line);
                csvWriter.Flush(); // 立即写入磁盘
            }
            catch (Exception ex)
            {
                MessageBox.Show("写入 CSV 失败：" + ex.Message);
            }
        }
        public void StopCsvLogging()
        {
            if (!isLogging) return;

            try
            {
                csvWriter?.Flush();
                csvWriter?.Close();
                csvWriter = null;

                isLogging = false;
                MessageBox.Show("CSV 日志已停止");
            }
            catch (Exception ex)
            {
                MessageBox.Show("关闭 CSV 失败：" + ex.Message);
            }
        }



    }
}
